package com.itsu.vtalk.component.websocket;

import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.itsu.vtalk.entity.Message;
import com.itsu.vtalk.service.impl.MessageServiceBase;
import com.itsu.vtalk.util.SpringContextUtil;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.io.IOException;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author suben
 * @createtime 2020/6/20 14:18
 */
@Component
@ServerEndpoint("/socket/{userId}")
public class VtalkWebSocketComponent {

    private static Logger logger = LoggerFactory.getLogger(VtalkWebSocketComponent.class);

    private static ConcurrentHashMap<String, VtalkWebSocketComponent> socketMap = new ConcurrentHashMap<>();

    private static AtomicInteger onlineCount = new AtomicInteger(0);

    private Session session;

    private String userId;

    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) throws Exception {
        this.userId = userId;
        this.session = session;
        if (socketMap.containsKey(userId)) {
            socketMap.remove(userId);
            socketMap.put(userId, this);
        } else {
            socketMap.put(userId, this);
            addCount();
        }
        MessageServiceBase messageService = SpringContextUtil.getBean(MessageServiceBase.class);
        List<Message> messages = messageService.getLast30DaysMessage(null, userId);
        for (Message message : messages) {
            sendMessage(JSON.toJSONString(message));
        }
//        broadcast("This is a System message");
    }


    @OnClose
    public void onClose() {
        if (socketMap.containsKey(userId)) {
            socketMap.remove(userId);
            decreaseCount();
        }
        logger.info("a user is offline, which id: {}", userId);
    }

    @OnError
    public void onError(Throwable throwable) {
        logger.error("something wrong happend, userId: " + userId, throwable);
    }

    @OnMessage
    public void onMessage(String message, Session session) throws Exception {
        if (StringUtils.isNotBlank(message)) {
            JSONObject jsonObject = null;
            try {
                jsonObject = JSON.parseObject(message);
            } catch (Exception e) {
                logger.error("can not deserialization send message to a Json object");
                throw e;
            }
            jsonObject.put("fromUserId", userId);
            String toUserId = (String) jsonObject.get("toUserId");
            if (StringUtils.isBlank(toUserId)) {
                throw new IllegalArgumentException("toUserId can not be empty");
            }
            if ("ALL".equalsIgnoreCase(toUserId)) {
                // 群发
                for (Map.Entry<String, VtalkWebSocketComponent> entry : socketMap.entrySet()) {
                    String userId = entry.getKey();
                    VtalkWebSocketComponent vtalkWebSocketComponent = entry.getValue();
                    if (!this.userId.equals(userId)) {
                        vtalkWebSocketComponent.sendMessage(JSON.toJSONString(jsonObject));
                    }
                }
            } else {
                // 私聊
                if (socketMap.containsKey(toUserId)) {
                    socketMap.get(toUserId).sendMessage(JSON.toJSONString(jsonObject));
                } else {
                    logger.info("target user is not online");
                    //存表，当目标user下一次上线时自动发送
                    MessageServiceBase messageService = SpringContextUtil.getBean(MessageServiceBase.class);
                    Message msgObj = new Message();
                    msgObj.setMessageId(IdUtil.fastUUID());
                    msgObj.setContent(jsonObject.getString("content"));
                    msgObj.setCreateTime(new Date());
                    msgObj.setFromUserId(userId);
                    msgObj.setToUserId(toUserId);
                    messageService.saveUserMessage(msgObj);
                }
            }
        }
    }


    private void sendMessage(String message) throws IOException {
        this.session.getBasicRemote().sendText(message);
    }

    public static void broadcast(String message) throws IOException {
        for (Map.Entry<String, VtalkWebSocketComponent> entry : socketMap.entrySet()) {
            VtalkWebSocketComponent vtalkWebSocketComponent = entry.getValue();
            vtalkWebSocketComponent.sendMessage(JSON.toJSONString(message));
        }
    }

    private static void addCount() {
        onlineCount.addAndGet(1);
    }

    public static int getCount() {
        return onlineCount.get();
    }

    private static void decreaseCount() {
        onlineCount.decrementAndGet();
    }
}
